package com.zyf.chapter01.principle.practice;


import com.zyf.chapter01.principle.SOLID.SRP.utils.Gson;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 相当于上帝类
 * 定时根据给定的时间区间，从数据库中取出数据
 * 借助 {@link Aggregator} Aggregator 类完成统计工作
 * 将统计结果输出到命令行
 * <br />
 * TODO {@link ConsoleReporter} 和 {@link EmailReporter} 中存在代码重复问题
 *   做统计的逻辑是相同，违反了 DRY 原则，且职责不够单一（如显示操作等逻辑），
 *   其次代码中设计线程操作，并调用了{@link Aggregator}的静态函数，所以可测试性不好
 *
 * @author yifeng
 * @see Aggregator
 */
public class ConsoleReporter {
    private MetricsStorage metricsStorage;
    private ScheduledExecutorService executor;

    public ConsoleReporter(MetricsStorage metricsStorage) {
        this.metricsStorage = metricsStorage;
        this.executor = executor = Executors.newSingleThreadScheduledExecutor();
    }

    // 第 4 个代码逻辑:定时触发第 1、 2、 3代码逻辑的执行
    public void startRepeatedReport(long periodInSeconds, long durationInSeconds) {
        executor.scheduleAtFixedRate((Runnable) () -> {
            // 第一个代码逻辑：根据给定的时间区间，从数据库中拉取数据;
            long durationInMillis = durationInSeconds * 1000;
            long endTimeInMillis = System.currentTimeMillis();
            long startTimeInMillis = endTimeInMillis - durationInMillis;
            Map<String, List<RequestInfo>> requestInfos =
                    metricsStorage.getRequestInfos(startTimeInMillis, endTimeInMillis);
            HashMap<String, RequestStat> stats = new HashMap<>();
            for (Map.Entry<String, List<RequestInfo>> entry : requestInfos.entrySet()) {
                String apiName = entry.getKey();
                List<RequestInfo> requestInfosPerApi = entry.getValue();
                // 第二个代码逻辑；将统计数据显示到中断，计算得到统计数据
                RequestStat requestStat = Aggregator.aggregate(requestInfosPerApi, durationInMillis);
                stats.put(apiName, requestStat);
            }
            // 第三个代码逻辑：将统计数据显示到终端(命令行或邮件);
            System.out.println("Time Span: [ " + startTimeInMillis + "," + endTimeInMillis + " ]");
            Gson gson = new Gson();
            System.out.println(gson.toJson(stats));

        }, 0, periodInSeconds, TimeUnit.SECONDS);
    }
}
